package cn.virens.cmpt.rabbit;

import java.io.IOException;
import java.util.Objects;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.Envelope;
import com.rabbitmq.client.ShutdownSignalException;

import cn.virens.cmpt.rabbit.packet.RabbitHeaders;
import cn.virens.cmpt.rabbit.packet.RabbitPacket;
import cn.virens.cmpt.rabbit.packet.reply.RabbitPacketReply;
import cn.virens.common.exception.ExceptionUtil;
import cn.virens.common.utils.MapUtil;
import cn.virens.common.utils.common.CloseableUtil;

public class RabbitConsumer implements Consumer {
	private final RabbitManagerImpl rabbitManager;

	protected RabbitConsumer(RabbitManagerImpl rabbitManager) {
		this.rabbitManager = rabbitManager;
	}

	@Override
	public void handleConsumeOk(String consumerTag) {

	}

	@Override
	public void handleCancelOk(String consumerTag) {

	}

	@Override
	public void handleCancel(String consumerTag) throws IOException {

	}

	@Override
	public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] bytes) throws IOException {
		RabbitConsumerProps props = new RabbitConsumerProps(rabbitManager.mChannel, consumerTag);

		// 获取指令包参数：是否等待应答、指令码、设备地址
		props.setReply(MapUtil.getBoolean(properties.getHeaders(), RabbitHeaders.REPLY));
		props.setCmd(MapUtil.getString(properties.getHeaders(), RabbitHeaders.CMD));
		props.setMac(MapUtil.getString(properties.getHeaders(), RabbitHeaders.MAC));

		// 将消息参数缓存到对象数据中
		props.setProperties(Objects.requireNonNull(properties));
		props.setEnvelope(Objects.requireNonNull(envelope));

		try {
			handler(props, bytes);
		} catch (Exception e) {
			exceptionReply(props, e);
		} finally {
			CloseableUtil.close(props);
		}
	}

	@Override
	public void handleShutdownSignal(String consumerTag, ShutdownSignalException sig) {

	}

	@Override
	public void handleRecoverOk(String consumerTag) {

	}

	// 遍历可用数据处理单元，如果能处理就进行处理
	private void handler(RabbitConsumerProps props, byte[] bytes) throws Exception {
		for (RabbitConsumerHandler<? extends RabbitPacket> h : rabbitManager.mHandlers) {
			if (h.isSupport(props.getCmd())) h.doHandler(props, bytes);
		}
	}

	private void exceptionReply(RabbitConsumerProps props, Exception e) throws IOException {
		if (props.getReply() != null && Boolean.TRUE.equals(props.getReply())) {
			RabbitPacketReply packetReply = new RabbitPacketReply();
			packetReply.setMessage(ExceptionUtil.getMessage(e));
			packetReply.setCode(ExceptionUtil.getCode(e));

			rabbitManager.sendReply(props, packetReply);
		}
	}

}
